package com.yuju.controller.base;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;

import com.alibaba.fastjson.JSON;
import com.yuju.common.Result;
import com.yuju.common.util.collection.CollectionUtilss;
import com.yuju.enums.ReturnCodeEnum;
import com.yuju.enums.ReturnStatusEnum;
import com.yuju.exception.BusinessException;
import com.yuju.model.SessionInfo;
import com.yuju.model.User;
import com.yuju.model.UserModel;
import com.yuju.util.WebUtil;

public class BaseController<V, M> {
	private static ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal<HttpServletRequest>();
	private static ThreadLocal<HttpServletResponse> responseThreadLocal = new ThreadLocal<HttpServletResponse>();
	private static ThreadLocal<HttpSession> sessionThreadLocal = new ThreadLocal<HttpSession>();
	private static ThreadLocal<ServletContext> servletContextThreadLocal = new ThreadLocal<ServletContext>();
	private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
	private Class<M> persistentClass;
	
	/**
	 * 从每次的请求中得到HttpServlet对象并赋值
	 * 
	 * @author xue
	 * @since 2016-06-03
	 * @param request
	 *            当前请求的request对象
	 * @param response
	 *            当前响应的response
	 * @param session
	 *            当前会话对象
	 */
	@ModelAttribute
	public void intHttpServlet(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
		requestThreadLocal.set(request);
		responseThreadLocal.set(response);
		sessionThreadLocal.set(session);
		servletContextThreadLocal.set(session.getServletContext());
	}
	
	@ExceptionHandler
	public void exp(HttpServletRequest request, HttpServletResponse response, Exception ex) throws IOException {
		Result result = null;
		if (ex instanceof BusinessException) {
			BusinessException be = (BusinessException) ex;
			result = error(be);
			ex.printStackTrace();
		} else {
			ex.printStackTrace();
			logger.warn("系统错误"+ex.getMessage());
			System.out.println(ex);
			result = error(ReturnCodeEnum.UMKNOWN_ERROR.getCode());
		}
		response.setCharacterEncoding("UTF-8");  
	    response.setContentType("application/json; charset=utf-8");
		PrintWriter pw = response.getWriter();
		pw.print(response(result));
		pw.flush();
		pw.close();
	}
	
	/**
	 * 功能：响应客户端数据<br/>
	 *
	 * @author xuehj
	 * @Date 2017年9月12日 下午4:12:33 <br/>
	 */
	protected String response(Result result) {
		return JSON.toJSONString(result);
	}
	
	/**
	 * 
	 * 功能：参数验证错误，返回错误集<br/>
	 *
	 * @author xuehj
	 * @Date 2017年9月12日 下午4:10:43 <br/>
	 */
	protected Result validateError(Map<String, String> failure) {
		Result result = new Result();
		result.setStatus(ReturnStatusEnum.FAILURE.getCode());
		result.setMsg(ReturnStatusEnum.FAILURE.getDesc());
		result.setReturnCode(ReturnCodeEnum.VALIDATE_ERROR.getCode());
		result.setReturnMsg(ReturnCodeEnum.VALIDATE_ERROR.getDesc());
		
		result.setValidateMsg(failure);
		
		return result;
	}
	
	/**
	 * 功能：<br/>
	 *
	 * @author xuehj
	 * @param exception 业务异常
	 * @Date 2017年9月12日 下午6:13:24 <br/>
	 */
	protected Result error(BusinessException exception) {
		Result result = new Result();
		result.setStatus(ReturnStatusEnum.FAILURE.getCode());
		result.setMsg(ReturnStatusEnum.FAILURE.getDesc());
		result.setReturnCode(exception.getReturnCode());
		result.setReturnMsg(exception.getReturnMsg());
		return result;
	}
	
	/**
	 * 功能：<br/>
	 *
	 * @author xuehj
	 * @param returnCode 业务代码
	 * @Date 2017年9月12日 下午6:13:24 <br/>
	 */
	protected Result error(String returnCode) {
		Result result = new Result();
		result.setStatus(ReturnStatusEnum.FAILURE.getCode());
		result.setMsg(ReturnStatusEnum.FAILURE.getDesc());
		result.setReturnCode(returnCode);
		result.setReturnMsg(ReturnCodeEnum.getDescByCode(returnCode));
		return result;
	}
	
	/**
	 * 功能：<br/>
	 *
	 * @author xuehj
	 * @param returnCode 业务代码
	 * @Date 2017年9月12日 下午6:13:24 <br/>
	 */
	protected Result error(String returnCode, String returnMsg) {
		Result result = new Result();
		result.setStatus(ReturnStatusEnum.FAILURE.getCode());
		result.setMsg(ReturnStatusEnum.FAILURE.getDesc());
		result.setReturnCode(returnCode);
		result.setReturnMsg(returnMsg);
		return result;
	}
	
	/**
	 * 功能：初始化用户会话信息<br/>
	 *
	 * @author xuehj
	 * @Date 2017年9月20日 下午2:55:40 <br/>
	 */
	public String initSessionInfo(UserModel vipInfo) {
		SessionInfo sessionInfo = WebUtil.createSessionInfo(vipInfo);
		String token = null;//sessionManager.createSession(sessionInfo);
		WebUtil.addCookie4Token(getResponse(), sessionInfo);
		return token;
	}

	/**
	 * 获得request
	 * 
	 * @return
	 */
	public HttpServletRequest getRequest() {
		return requestThreadLocal.get();
	}

	/**
	 * 获得response
	 * 
	 * @return
	 */
	public HttpServletResponse getResponse() {
		return responseThreadLocal.get();
	}
	
	/**
	 * 功能：获取系统用户<br/>
	 *
	 * @author xuehj
	 * @param token Token
	 * @Date 2017年9月27日 上午10:06:31 <br/>
	 */
	public User getUser() {
		try {
			return getSessionInfo().getUser();
		} catch(Exception e) {
			return null;
		}
	}
	
	/**
	 * 功能：得到回话信息<br/>
	 *
	 * @author xuehj
	 * @param token Token
	 * @Date 2017年9月27日 上午10:07:59 <br/>
	 */
	public SessionInfo getSessionInfo() {
		return null;//sessionManager.getSession(getToken());
	}
	
	/**
	 * 功能：从请求中获取参数<br/>
	 *
	 * @author xuehj
	 * @Date 2017年9月27日 上午10:10:52 <br/>
	 */
	public String getParameter(String key) {
		return requestThreadLocal.get().getParameter(key);
	}
	
	public String getToken() {
		return getParameter("token");
	}
	
	/**
	 * 功能：VO转换PO<br/>
	 * @param from VO对象
	 * @param clazz PO类型对象
	 * @author xuehj
	 * @Date 2017年9月16日 下午12:02:15 <br/>
	 */
	public M convert(V from, Class<M> clazz) {
		if (from == null) {
			return null;
		}
		M to = null;
		try {
			to = clazz.newInstance();
		} catch (Exception e) {
		}
		convert(from, to);
		
		return to;
	}
	
	public List<M> convert(List<V> fromList) {
		if (CollectionUtilss.isEmpty(fromList)) {
            return null;
        }
		this.persistentClass = (Class<M>)getSuperClassGenricType(getClass(), 1);
		return convert(fromList, this.persistentClass);
	}
	
	/**
     * 批量对象转换
     */
    public List<M> convert(List<V> fromList, Class<M> clazz) {
        if (CollectionUtilss.isEmpty(fromList)) {
            return null;
        }
        List<M> toList = new ArrayList<M>();
        for (V from : fromList) {
            toList.add(convert(from, clazz));
        }
        return toList;
    }
	
	/**
	 * 功能：属性拷贝<br/>
	 * @param from PO对象
	 * @param to Model对象
	 * @author xuehj
	 * @Date 2017年9月16日 下午12:01:02 <br/>
	 */
	protected void convert(V from, M to) {
//		BeanMappingUtil.copy(from, to);
		try {
			BeanUtils.copyProperties(to, from);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 功能：VO转换成PO<br/>
	 * @param from VO对象
	 * @author xuehj
	 * @Date 2017年9月16日 下午12:00:41 <br/>
	 */
	public M convert(V from) {
		this.persistentClass = (Class<M>)getSuperClassGenricType(getClass(), 1);
		return convert(from, this.persistentClass);
	}
    
    @SuppressWarnings("unchecked")
    private static Class<Object> getSuperClassGenricType(final Class clazz, final int index) {
    	// 返回表示此Class所表示的实体（类、接口、基本类型或void）的直接超类的Type
    	Type genType = clazz.getGenericSuperclass();
    	
    	if (!(genType instanceof ParameterizedType)) {
    		return Object.class;
    	}
    	
    	// 返回表示此类型实际类型参数的Type对象数组
    	Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
    	
    	if (index >= params.length || index < 0) {
    		return Object.class;
    	}
    	
    	if (!(params[index] instanceof Class)) {
    		return Object.class;
    	}
    	
    	return (Class) params[index];
    }
}
